/*
 *      network_list.cpp
 *
 *      Copyright 2009 AzureSky <AzureSky.fedora@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#include "network_list.h"

network_list::network_list():m_ipv4_tcp_path("/proc/net/tcp"),
								m_ipv4_udp_path("/proc/net/udp")
{
	init_data();
	m_network_list.clear();
}

network_list::~network_list()
{
	clear_all();
}

void network_list::init_data(){
	PROTOCOL.push_back("TCP");
	PROTOCOL.push_back("UDP");

	STATUS.push_back("ERROR_STATUS");
	STATUS.push_back("ESTABLISHED");
	STATUS.push_back("SYN_SENT");
	STATUS.push_back("SYN_RECV");
	STATUS.push_back("FIN_WAIT1");
	STATUS.push_back("FIN_WAIT2");
	STATUS.push_back(	"TIME_WAIT");
	STATUS.push_back(	"CLOSE");
	STATUS.push_back(	"CLOSE_WAIT");
	STATUS.push_back(	"LAST_ACK");
	STATUS.push_back(	"LISTEN");
	STATUS.push_back(	"CLOSING");
}

void network_list::read()
{
	read_file(m_ipv4_tcp_path,network_list::TCP);
	read_file(m_ipv4_udp_path,network_list::UDP);

	start();
}

void network_list::refresh()
{
	clear_all();
	read();
}

void network_list::clear_all()
{
	NETWORK_LIST::iterator network_it = m_network_list.begin();
	for(;network_it != m_network_list.end();network_it++){
		delete (*network_it);
		(*network_it) = NULL;
	}
	m_network_list.clear();
}

void network_list::read_file(const std::string& path,network_list::ip_protocol protocol)
{
    std::ifstream file(path.c_str());
    if(file.peek() == EOF){
    	std::cout << " error " << std::endl;
    	return;
    }

    std::string line_string;
    bool is_found = false;
    while(getline(file,line_string)){
    	if(is_found){
    		add_link(line_string,protocol);
    	}
    	else{
        	if(line_string.find("sl",0) != std::string::npos){
        		is_found = true;
        	}
    	}
    }
}

void network_list::add_link(const std::string& link,network_list::ip_protocol protocol)
{
	int ID = 0;
	int local_port = 0;
	int remote_port = 0;
	int status = 0;
	char local_address[9];
	char remote_address[9];
	memset(local_address, 0, sizeof(local_address));
	memset(remote_address, 0, sizeof(remote_address));

	int result = sscanf(link.c_str(), " %d: %8[0-9A-Fa-f]:%X %8[0-9A-Fa-f]:%X %X ",
						&ID,
						local_address,&local_port,
						remote_address,&remote_port,
						&status);

	if(result == -1 || local_port == 0 || remote_port == 0){
		return;
	}

	net_link_ptr p_network_link = new net_link;
	memset(p_network_link,0,sizeof(p_network_link));

	p_network_link->protocol = protocol;
	if(to_ip4(p_network_link->local_ip,local_address) == -1){
		delete p_network_link;
		return ;
	}
	p_network_link->local_port = local_port;
	if(to_ip4(p_network_link->remote_ip,remote_address) == -1){
		delete p_network_link;
		return ;
	}
	p_network_link->remote_port = remote_port;
	p_network_link->status = status;

	m_network_list.push_back(p_network_link);
}

int network_list::to_ip4(std::string& ip_address,char ip[])
{
	if(ip == NULL){
		return -1;
	}

	char ip_buff[9];
	memset(ip_buff, 0, sizeof(ip_buff));
	int result = sprintf(ip_buff, "%c%c%c%c%c%c%c%c",
							ip[6],  ip[7],  ip[4],  ip[5],
							ip[2],  ip[3],  ip[0],  ip[1]);

	if(result == -1){
		return -1;
	}

	int one = 0;
	int two = 0;
	int three = 0;
	int four = 0;

	sscanf(ip_buff,"%2X%2X%2X%2X",&one,&two,&three,&four);

	std::ostringstream str;
	str << one;
	str << ".";
	str << two;
	str << ".";
	str << three;
	str << ".";
	str << four;
	
	ip_address = str.str();
	return 0;
}

void network_list::start()
{
	m_list_it = m_network_list.begin();
}

bool network_list::next()
{
	if(is_end()){
		return false;
	}

	m_list_it++;
	if(!is_end()){
		return true;
	}

	if(is_end()){
		return false;
	}
}

bool network_list::is_end()
{
	return (m_list_it == m_network_list.end());
}

std::string& network_list::get_ip_protocol()
{
	return PROTOCOL.at(static_cast<int>((*m_list_it)->protocol));
}

std::string& network_list::get_local_ip()
{
	return (*m_list_it)->local_ip;
}

int network_list::get_local_port()
{
	return (*m_list_it)->local_port;
}

std::string& network_list::get_remote_ip()
{
	return (*m_list_it)->remote_ip;
}

int network_list::get_remote_port()
{
	return (*m_list_it)->remote_port;
}

std::string& network_list::get_ip_status()
{
	return STATUS.at((*m_list_it)->status);
}
